﻿using Microsoft.OpenApi.Models; // 引入 OpenApi 规范中模型相关类的命名空间
using Swashbuckle.AspNetCore.SwaggerGen; // 引入 Swashbuckle.AspNetCore 用于生成 Swagger 文档的命名空间
using System.ComponentModel; // 引入 System.ComponentModel 命名空间，其中包含 DefaultValueAttribute
using System.Reflection; // 引入 System.Reflection 命名空间，用于反射（获取类型和属性信息）

// 定义一个名为 DefaultValueSchemaFilter 的公共类，它实现了 ISchemaFilter 接口
// ISchemaFilter 接口用于在 Swagger Schema 生成过程中进行自定义修改
public class DefaultValueSchemaFilter : ISchemaFilter
{
    // 实现 ISchemaFilter 接口的 Apply 方法
    // 这个方法会在每个模型（Schema）生成时被调用
    // schema: 当前正在处理的 OpenAPI Schema 对象，代表一个数据模型
    // context: SchemaFilter 的上下文，提供了关于当前 Schema 的更多信息，例如原始 C# 类型
    public void Apply(OpenApiSchema schema, SchemaFilterContext context)
    {
        // 检查当前 schema 的属性集合是否为空。如果为空，则没有可处理的属性
        if (schema?.Properties == null)
        {
            // 如果属性集合为空，则直接返回，不执行后续逻辑
            return;
        }

        // 遍历当前 schema 中的每一个属性
        // property.Key 是属性的名称（例如 "userName"），property.Value 是对应的 OpenApiSchema 对象
        foreach (var property in schema.Properties)
        {
            var propertyName = property.Key; // 获取当前正在处理的属性的名称（通常是 camelCase）
            var schemaProperty = property.Value; // 获取当前属性对应的 OpenApiSchema 对象

            // 尝试通过反射获取原始 C# 类型中与当前属性名称匹配的 PropertyInfo 对象
            // context.Type 是当前 Schema 对应的 C# 类型
            // BindingFlags 用于指定搜索属性的范围：公共 (Public)、实例 (Instance)、不区分大小写 (IgnoreCase)
            var modelProperty = context.Type.GetProperties(BindingFlags.Public | BindingFlags.Instance)
                                        .FirstOrDefault(p => string.Equals(p.Name, propertyName, StringComparison.OrdinalIgnoreCase));

            // 确保找到了对应的 C# 属性
            if (modelProperty != null)
            {
                // 尝试获取 C# 属性上是否存在 DefaultValueAttribute 特性
                var defaultValueAttribute = modelProperty.GetCustomAttribute<DefaultValueAttribute>();
                // 如果存在 DefaultValueAttribute 特性
                if (defaultValueAttribute != null)
                {
                    // 将 DefaultValueAttribute 的值转换为 OpenApiString 类型，并设置给 schemaProperty 的 Default 属性
                    // Default 属性在 OpenAPI 规范中表示该属性的默认值
                    schemaProperty.Default = new Microsoft.OpenApi.Any.OpenApiString(defaultValueAttribute.Value?.ToString());
                    // 同样，将 DefaultValueAttribute 的值设置给 schemaProperty 的 Example 属性
                    // Example 属性在 Swagger UI 中通常用于显示一个示例值，有时比 Default 属性更直观
                    schemaProperty.Example = new Microsoft.OpenApi.Any.OpenApiString(defaultValueAttribute.Value?.ToString());
                }
                else // 如果没有 DefaultValueAttribute 特性
                {
                    // 尝试从 C# 属性的直接初始化器中获取默认值（例如 public string Name { get; set; } = "abc";）
                    try
                    {
                        // 创建当前 Schema 对应 C# 类型的一个默认实例（例如 new LoginDto()）
                        var defaultValue = Activator.CreateInstance(context.Type)?.GetType()
                            // 获取该实例中当前属性的值
                            .GetProperty(modelProperty.Name)?.GetValue(Activator.CreateInstance(context.Type));

                        // 如果获取到的默认值不为空，且不是一个空字符串（避免将空字符串作为示例）
                        if (defaultValue != null && !string.IsNullOrEmpty(defaultValue.ToString()))
                        {
                            // 将获取到的默认值设置给 schemaProperty 的 Default 属性
                            schemaProperty.Default = new Microsoft.OpenApi.Any.OpenApiString(defaultValue.ToString());
                            // 同样设置给 Example 属性
                            schemaProperty.Example = new Microsoft.OpenApi.Any.OpenApiString(defaultValue.ToString());
                        }
                    }
                    catch (Exception)
                    {
                        // 在尝试获取默认值时捕获任何异常，并忽略它们
                        // 这是为了避免在某些复杂类型或无参构造函数缺失的情况下导致程序崩溃
                    }
                }
            }
        }
    }
}